Skip to content

A task's instructions as a tab: openFile, read-only Markdown as a page - #39

Merged
cedricvogel-leo merged 2 commits into
mainfrom
feature/instructions-tab
Nov 6, 2026
Merged

cedricvogel-leo merged 2 commits into
mainfrom
feature/instructions-tab

Conversation

@cedricvogel-leo

@cedricvogel-leo cedricvogel-leo commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

P45: a task's instructions as a tab in an IDE project. A link opens on aufgabe.md, read-only and shown as a page, next to the code.

Installs glpython-editor v0.1.29 (#55: the page view, and «Visualisieren» with another tab open).

What it does

  1. Start tab in the link: an optional "openFile" next to mainFile, in any link version.
    • Without it, the link opens on mainFile as before. An openFile that isn't among the files is ignored, and an IDE from before opens such a link as it did.
    • The tab's project keeps it (also after a reload), as do «Teilen», the ZIP (glpython.json) and a ZIP import. It follows a rename, and a delete drops it.
    • By URL: openFile can name a file loaded by URL (a shorter hand-in link: 1,973 instead of 3,606 characters). That tab becomes the open one as soon as it has loaded, unless the learner has chosen a tab in the meantime. If it fails, mainFile stays open. A read-only .md by URL opens as the page.
    • Tab order: the tabs follow the order of the files in the link, with libraries by URL among them, so aufgabe.md can come first. «Teilen» writes the files in that order, and a new file comes last.
  2. ▶, «Tests», «Visualisieren» act on mainFile, whichever tab is open. ▶ and «Tests» already did. «Visualisieren» ran mainFile but drew an empty view with another tab open; glpython-editor#55 fixes that.
  3. Read-only files with their code: readOnly: true on a file with code already worked, and is now checked:
    • links accept it;
    • the drawer shows the lock, with no rename or delete;
    • the editor is read-only;
    • «Teilen», the stored copy and the ZIP keep it.
  4. Markdown as a page:
    • Switch: a .md tab gets Ansicht / Text at the end of the tabs. A read-only file opens as the page, an editable one as its text.
    • Renderer: marked 18.1.1 with DOMPurify 3.4.17, both pinned exactly. I took the newest marked that's at least two weeks old, since 18.1.3 is four days old.
    • Safety: HTML written in the Markdown shows as text (marked's html renderer escapes it), and DOMPurify sanitizes the result. Links get target="_blank" and rel="noopener noreferrer".
    • Code is only shown: not highlighted, not run.
    • Look: the styling is in the editor's tokens (#55).
  5. Compatible: the embed's «In IDE öffnen» links don't write the new fields and open as before.

The fields (for your link script)

As ?project= (or #project= beyond 8,192 characters) + LZString.compressToEncodedURIComponent(JSON.stringify(payload)):

{
  "v": 2,
  "name": "Etappe 4: Auswerter",
  "mainFile": "auswerter.py",
  "openFile": "aufgabe.md",
  "files": {
    "aufgabe.md": { "path": "aufgabe.md", "url": "https://…/aufgabe.md", "readOnly": true },
    "parser.py": { "path": "parser.py", "url": "https://…/parser.py", "readOnly": true },
    "auswerter.py": { "path": "auswerter.py", "label": "auswerter.py", "kind": "python", "code": "…" }
  }
}

aufgabe.md can also carry its code ("kind": "text", "code": "…", "readOnly": true); then it is open at once.

  • v: 2 because of the library by URL; a link without libraries can stay at 1.
  • kind: "text" for the Markdown file.
  • openFile: a key of files.

Checks (test:browser, all 18 pass)

New cases:

  • Task link (auswerter.py main, bib.py by URL, aufgabe.md with code, read-only, openFile):
    • opens on aufgabe.md as a page, with the heading, table, code block and link (_blank, noopener noreferrer);
    • «Text» shows it read-only, and typing changes nothing;
    • the drawer shows the lock, with no rename or delete;
    • with aufgabe.md open, ▶ prints auswerter.py's output, «Tests» runs its doctest, and «Visualisieren» shows auswerter.py.
  • «Teilen» and reload:
    • the copied link has openFile, mainFile, aufgabe.md with readOnly: true and its code, and bib.py by URL;
    • after a reload the IDE opens on the page again, and the stored copy keeps readOnly.
  • Task by URL (aufgabe.md first in the link, served by the check):
    • it opens on aufgabe.md as a page once it has loaded;
    • the tabs are aufgabe.md, bib.py, auswerter.py, in the link's order;
    • «Teilen» keeps openFile, the order and the URL, and so does a reload.
  • Slow URL (3 s): the IDE shows auswerter.py until it has loaded. The learner opens bib.py, and aufgabe.md arriving doesn't take the tab.
  • Failing URL (404): auswerter.py stays open, with the notice.
  • Old link: opens on main.py (an unknown openFile is ignored), and an editable .md opens as text.
  • Sanitizing: <script>, <img onerror>, a javascript: link and onclick do nothing. The HTML shows as text, no such element or attribute remains, the link has no href, and clicking it sets nothing.

Lint passes (only the existing warnings in coi-serviceworker.js), and so does the build. THIRD_PARTY_NOTICES.md now lists marked (MIT) and DOMPurify (Apache-2.0, of MPL-2.0 OR Apache-2.0).

Manual tests

Desktop (Chrome, Safari, Firefox), with a task link:

  1. It opens on aufgabe.md as a page with «Ansicht» pressed.
  2. «Text», then «Ansicht»: switches. Scroll the page with the mouse and with the keyboard (Tab into the page, then the arrow keys).
  3. A link in the page opens in a new tab.
  4. ▶, «Tests» and «Visualisieren» with aufgabe.md open: they all act on auswerter.py.
  5. Edit auswerter.py, «Teilen», then open the copied link in a new tab: it opens on aufgabe.md, with the edit.
  6. ⋮ «Projekt herunterladen», then open the ZIP again: aufgabe.md is read-only and open at the start.
  7. An old course link: as before.

iPad (portrait and landscape), with an external keyboard:

  1. The page is readable, and wide tables and code blocks scroll sideways on their own.
  2. The switch can be tapped, and Tab or ⌥ Tab reaches it.
  3. In «Text», the keyboard can't change the file.
  4. ▶ from the top bar runs auswerter.py.

Follow-ups (not done)

  • The drawer lists aufgabe.md by URL under «Bibliotheken» (now with the book icon). For instructions, another heading, e.g. «Geladene Dateien», might read better.
  • ZIP: a ZIP doesn't keep the tab order.
  • The «Ansicht / Text» choice isn't remembered across a reload; each file starts in its default.
  • Images: HTTPS images in the Markdown are allowed and load from their server. Relative image paths don't resolve, since the project has no image files.
  • Bundle size: the IDE bundle grows from 157.8 to 183.4 KB gzipped (measured; mostly marked and DOMPurify, plus the editor changes since v0.1.27). They could be loaded only when a Markdown file opens.

🤖 Generated with Claude Code

cedricvogel-leo and others added 2 commits November 6, 2026 17:15
Share links can name the tab to open with ("openFile", e.g. a task's
aufgabe.md); the tab's project, «Teilen», a reload and the ZIP keep it,
and it follows a rename. ▶, Tests and Visualisieren act on mainFile,
whichever tab is open. Markdown files get the workspace's page view
(glpython-editor#55) through renderMarkdown: marked + DOMPurify,
pinned; HTML in the Markdown shows as text, links open in a new tab.

Checks in test:browser: a task link (opens on aufgabe.md as a page, the
buttons act on auswerter.py, read-only, «Teilen» and reload keep it),
an old link, and sanitizing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A library by URL named as openFile (e.g. aufgabe.md, for a shorter
hand-in link) becomes the open tab once fetched, unless the learner has
chosen a tab meanwhile; one that fails leaves mainFile open. A read-only
.md by URL opens as the page. The tabs follow the files' order in the
link (fileOrder on the tab's project), and «Teilen» writes them in that
order. glpython-editor at v0.1.29 (#55).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cedricvogel-leo
cedricvogel-leo merged commit 1b091de into main Nov 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant